﻿using System;
using System.Collections.Generic;
using MathExpression;
using NUnit.Framework;
using SimplexSolver;

namespace LPTask.Test
{
    [TestFixture]
    public class TargetParamSimplexSolverFixture
    {
        private SolverComposition _solver;

        [TestFixtureSetUp]
        public void Initialize()
        {
            _solver = GlobalVariables.SolverComposition;
        }

        [Test]
        public void Solve()
        {
            ILPTask task = CreateTask();
            var deltaC = new[] {-1.0, 1.0, -1.0, -1.0};
            var solution = _solver.SolveParamTarget(task, deltaC) as ParameterSolution;
            Assert.IsNotNull(solution);
            Assert.Throws<NotImplementedException>(() => { var x = solution.Value; });
            SolutionItem[] items = solution.Items;
            Assert.AreEqual(2, items.Length);

            Assert.AreEqual(double.MinValue, items[0].Start);
            Assert.AreEqual(4.0/3.0, items[0].End);
            var solution1 = items[0].Item as SingleSolution;
            var data1 = solution1.Value.Data as PolynomialData;
            Assert.AreEqual(65.0, (data1.Values[0].Data as ScalarData).Value);
            Assert.AreEqual(-20.0, (data1.Values[1].Data as ScalarData).Value);
            IMathExpression[] x1 = solution1.X;
            Assert.AreEqual(15.0, (x1[0].Data as ScalarData).Value);
            Assert.AreEqual(0.0, (x1[1].Data as ScalarData).Value);
            Assert.AreEqual(5.0, (x1[2].Data as ScalarData).Value);
            Assert.AreEqual(0.0, (x1[3].Data as ScalarData).Value);

            Assert.AreEqual(4.0/3.0, items[1].Start);
            Assert.AreEqual(7.0, items[1].End);
            var solution2 = items[1].Item as SingleSolution;
            var data2 = solution2.Value.Data as PolynomialData;
            Assert.AreEqual(5.0, (data2.Values[0].Data as ScalarData).Value);
            Assert.AreEqual(25.0, (data2.Values[1].Data as ScalarData).Value);
            IMathExpression[] x2 = solution2.X;
            Assert.AreEqual(0.0, (x2[0].Data as ScalarData).Value);
            Assert.AreEqual(15.0, (x2[1].Data as ScalarData).Value);
            Assert.AreEqual(0.0, (x2[2].Data as ScalarData).Value);
            Assert.AreEqual(10.0, (x2[3].Data as ScalarData).Value);
        }

        private ILPTask CreateTask()
        {
            var task = new SimplexSolver.LPTask(4);
            var restrictions = new List<Restriction>
                                   {
                                       new Restriction(new[]
                                                           {
                                                               ExpressionFactory.Create(1.0),
                                                               ExpressionFactory.Create(1.0),
                                                               ExpressionFactory.Create(0.0),
                                                               ExpressionFactory.Create(0.0)
                                                           },
                                                       Restriction.EIneqMode.LessOrEqual,
                                                       ExpressionFactory.Create(15.0)),
                                       new Restriction(new[]
                                                           {
                                                               ExpressionFactory.Create(0.0),
                                                               ExpressionFactory.Create(1.0),
                                                               ExpressionFactory.Create(1.0),
                                                               ExpressionFactory.Create(-1.0)
                                                           },
                                                       Restriction.EIneqMode.LessOrEqual,
                                                       ExpressionFactory.Create(5.0)),
                                       new Restriction(new[]
                                                           {
                                                               ExpressionFactory.Create(0.0),
                                                               ExpressionFactory.Create(0.0),
                                                               ExpressionFactory.Create(1.0),
                                                               ExpressionFactory.Create(-1.0)
                                                           },
                                                       Restriction.EIneqMode.LessOrEqual,
                                                       ExpressionFactory.Create(10.0))
                                   };
            foreach (Restriction restriction in restrictions)
            {
                task.AddRestriction(restriction);
            }
            var target = new TargetFunction(new[]
                                                {
                                                    ExpressionFactory.Create(2.0),
                                                    ExpressionFactory.Create(5.0),
                                                    ExpressionFactory.Create(7.0),
                                                    ExpressionFactory.Create(-7.0)
                                                },
                                            TargetFunction.EDirection.Max);
            task.SetTargetFunction(target);
            return task;
        }
    }
}